package service

import (
	"github.com/nfnt/resize"
	"image"
	"image/jpeg"
	"io"
	"manboge/conf"
	"manboge/util" // 引入日志工具包
	"mime/multipart"
	"os"
	"strconv"
)

// UploadAvatarToLocalStatic 上传用户头像文件到本地静态资源目录
// 参数:
// - file: 头像文件，类型为multipart.File
// - userId: 用户ID，用于拼接文件路径
// - userName: 用户名，用于命名头像文件
// 返回值:
// - filePath: 文件存储路径
// - err: 错误信息，如果有的话
func UploadAvatarToLocalStatic(file multipart.File, userId uint, userName string) (filePath string, err error) {
	bId := strconv.Itoa(int(userId))                       // 将用户ID转为字符串，用于路径拼接
	basePath := "." + conf.AvatarPath + "user" + bId + "/" // 构建头像存储的基础路径
	if !DirExistOrNot(basePath) {                          // 检查目录是否存在
		util.LogrusObj.Info("创建目录: ", basePath) // 打日志记录目录创建
		CreateDir(basePath)                     // 不存在则创建
	}
	avatarPath := basePath + userName + ".jpg" // 定义头像文件路径，默认.jpg格式
	content, err := io.ReadAll(file)           // 读取文件内容
	if err != nil {
		util.LogrusObj.Error("读取头像文件失败: ", err)
		return "", err // 如果读取失败，返回错误
	}
	err = os.WriteFile(avatarPath, content, 0666) // 将内容写入指定文件路径
	if err != nil {
		util.LogrusObj.Error("写入头像文件失败: ", avatarPath, err)
		return "", err // 如果写入失败，返回错误
	}
	util.LogrusObj.Info("头像文件上传成功: ", avatarPath)
	return "user" + bId + "/" + userName + ".jpg", nil // 返回文件的相对路径
}

// UploadArticleToLocalStatic 上传文章图片文件到本地静态资源目录
// 参数:
// - file: 文章图片文件，类型为multipart.File
// - userId: 用户ID，用于拼接文件路径
// - articleName: 文章名称，用于命名文章文件
// 返回值:
// - filePath: 文件存储路径
// - err: 错误信息，如果有的话
func UploadArticleToLocalStatic(file multipart.File, userId string, articleName string) (filePath string, err error) {
	bId := userId                                             // 使用用户ID拼接路径
	basePath := "." + conf.ArticlePath + "writer" + bId + "/" // 构建文章图片存储的基础路径
	if !DirExistOrNot(basePath) {                             // 检查目录是否存在
		util.LogrusObj.Info("创建目录: ", basePath)
		CreateDir(basePath) // 不存在则创建
	}
	productPath := basePath + articleName + ".jpg" // 定义文章图片文件路径，默认.jpg格式
	content, err := io.ReadAll(file)               // 读取文件内容
	if err != nil {
		util.LogrusObj.Error("读取文章图片文件失败: ", err)
		return "", err // 如果读取失败，返回错误
	}
	err = os.WriteFile(productPath, content, 0666) // 将内容写入指定文件路径
	if err != nil {
		util.LogrusObj.Error("写入文章图片文件失败: ", productPath, err)
		return "", err // 如果写入失败，返回错误
	}
	util.LogrusObj.Info("文章图片文件上传成功: ", productPath)
	return "writer" + bId + "/" + articleName + ".jpg", nil // 返回文件的相对路径
}

// UploadArticleToLocalStaticByResize 上传并缩放文章图片文件到本地静态资源目录
// 使用nfnt/resize库进行图片的等比缩放，完成后删除临时文件
// 参数:
// - file: 文章图片文件，类型为multipart.File
// - userId: 用户ID，用于拼接文件路径
// - articleName: 文章名称，用于命名文章文件
// 返回值:
// - filePath: 文件存储路径
// - err: 错误信息，如果有的话
func UploadArticleToLocalStaticByResize(file multipart.File, userId string, articleName string) (filePath string, err error) {
	bId := userId                                             // 使用用户ID拼接路径
	basePath := "." + conf.ArticlePath + "writer" + bId + "/" // 构建文章图片存储的基础路径
	if !DirExistOrNot(basePath) {                             // 检查目录是否存在
		util.LogrusObj.Info("创建目录: ", basePath)
		CreateDir(basePath) // 不存在则创建
	}

	// 临时文件路径，保存上传的原始图片
	tempFilePath := basePath + articleName + "_temp.jpg"

	// 读取上传的文件内容
	content, err := io.ReadAll(file)
	if err != nil {
		util.LogrusObj.Error("读取文章图片文件失败: ", err)
		return "", err // 如果读取失败，返回错误
	}

	// 将内容写入临时文件
	err = os.WriteFile(tempFilePath, content, 0666)
	if err != nil {
		util.LogrusObj.Error("写入临时文件失败: ", tempFilePath, err)
		return "", err // 如果写入失败，返回错误
	}
	util.LogrusObj.Info("临时文件写入成功: ", tempFilePath)

	// 使用defer确保函数结束时删除临时文件
	defer os.Remove(tempFilePath)

	// 打开临时文件并解码图像
	tempFile, err := os.Open(tempFilePath)
	if err != nil {
		util.LogrusObj.Error("打开临时文件失败: ", tempFilePath, err)
		return "", err // 如果文件打开失败，返回错误
	}
	defer tempFile.Close()

	// 解码图片
	img, _, err := image.Decode(tempFile)
	if err != nil {
		util.LogrusObj.Error("解码临时文件图片失败: ", err)
		return "", err // 如果解码失败，返回错误
	}

	// 使用nfnt/resize库进行等比缩放，设置最大宽度800，高度375，保持纵横比
	m := resize.Thumbnail(800, 375, img, resize.Lanczos3)

	// 创建最终存储路径，存储缩放后的图片
	productPath := basePath + articleName + ".jpg"

	// 创建并保存缩放后的图像
	out, err := os.Create(productPath)
	if err != nil {
		util.LogrusObj.Error("创建缩放后文件失败: ", productPath, err)
		return "", err // 如果创建文件失败，返回错误
	}
	defer out.Close()

	// 将缩放后的图片编码为JPEG格式并写入文件
	err = jpeg.Encode(out, m, nil)
	if err != nil {
		util.LogrusObj.Error("编码JPEG图片失败: ", err)
		return "", err // 如果编码或写入失败，返回错误
	}
	util.LogrusObj.Info("文章图片缩放并保存成功: ", productPath)

	// 返回存储图片的相对路径
	return "writer" + bId + "/" + articleName + ".jpg", nil
}

// DirExistOrNot 判断文件夹路径是否存在
// 参数:
// - fileAddr: 文件夹路径
// 返回值:
// - bool: true表示存在，false表示不存在
func DirExistOrNot(fileAddr string) bool {
	s, err := os.Stat(fileAddr) // 获取文件信息
	if err != nil {
		util.LogrusObj.Warn("文件夹不存在: ", fileAddr)
		return false // 如果获取文件信息出错，认为文件夹不存在
	}
	return s.IsDir() // 判断该路径是否为文件夹
}

// CreateDir 创建文件夹
// 参数:
// - dirName: 文件夹路径
// 返回值:
// - bool: true表示创建成功，false表示创建失败
func CreateDir(dirName string) bool {
	err := os.MkdirAll(dirName, 0755) // 创建所有不存在的父级目录
	if err != nil {
		util.LogrusObj.Error("创建目录失败: ", dirName, err)
		return false // 如果创建出错，返回false
	}
	util.LogrusObj.Info("目录创建成功: ", dirName)
	return true // 创建成功
}

// DeleteFile 删除指定路径的文件
// 参数:
// - filePath: 要删除的文件的相对路径
// 返回值:
// - err: 错误信息，如果有的话
func DeleteFile(filePath string) error {
	// 构建完整的文件路径
	fullPath := "." + conf.ArticlePath + filePath

	// 删除文件
	err := os.Remove(fullPath)
	if err != nil {
		util.LogrusObj.Error("删除文件失败: ", fullPath, err)
		return err // 如果删除失败，返回错误信息
	}
	util.LogrusObj.Info("文件删除成功: ", fullPath)
	return nil // 删除成功，返回nil
}
